#ifndef cope_queue_cc
#define cope_queue_cc

#include "cope-queue.h"
#include <iostream>
#include <iomanip>


COPEPriQueue::COPEPriQueue(){        

    dsr_ = 0; //to indicate DSR protocol or not
    cope_vir_table_ = new VirQueue(); 
    prq_qh_.setIFQ(this);

}

COPEPriQueue::~COPEPriQueue() { 
   
}
//COPEPriQueue::initVirTable()
int COPEPriQueue::command(int argc, const char*const* argv) {
    Tcl& tcl = Tcl::instance();
    if(argc == 3) {
	if(strcmp(argv[1], "cope-init") == 0) {
	    if (strcmp(argv[2], "DSR") == 0) {
		dsr_ = 1; // IS A DSR	
	    } else {
		dsr_ = 0; // NON-DSR	
	    }
	    return (TCL_OK);

	} else {
	    TclObject *obj;
		
	    if( (obj = TclObject::lookup(argv[2])) == 0) {
		fprintf(stderr, "%s lookup failed\n", argv[1]);
		return TCL_ERROR;
	    }
	    if (strcmp(argv[1], "up-target") == 0) {
		if (*argv[2] == '0') {
		    up_target_ = 0;
		    return (TCL_OK);
		}
		up_target_ = (NsObject*) obj;
		if (up_target_ == 0) {
		    tcl.resultf("no such object %s", argv[2]);
		    return (TCL_ERROR);
		}
		return (TCL_OK);
	    }
	    if (strcmp(argv[1], "down-target") == 0) {
		if (*argv[2] == '0') {
		    down_target_ = 0;
		    return (TCL_OK);
		}
		down_target_ = (NsObject*) obj;
		if (down_target_ == 0) {
		    tcl.resultf("no such object %s", argv[2]);
		    return (TCL_ERROR);
		}
	    }
	}
    }

    if(dsr_) {
	return CMUPriQueue::command(argc, argv);
    } else {
	return PriQueue::command(argc, argv);
    }
   
}
void COPEPriQueue::setCOPEHandler(COPEHandler * h_cope) {
 
    h_cope_ = h_cope;
  
}
int COPEPriQueue::prq_assign_queue(Packet *p) {
    if(HDR_COPE(p)->ctype_ != COPE_DATA)
	return IFQ_RTPROTO;
    
    struct hdr_cmn *ch = HDR_CMN(p);    
    switch(ch->ptype()) {
    case PT_AODV:
    case PT_DSR:
    case PT_IMEP:
    case PT_MESSAGE:	/* used by DSDV */
    case PT_TORA:
	return IFQ_RTPROTO;

    case PT_AUDIO:
    case PT_VIDEO:
	return IFQ_REALTIME;

	// case PT_ACK:
	// 	return IFQ_LOWDELAY;

    default:
	return IFQ_NORMAL;
    }
}
void COPEPriQueue::showQueue(COPE* cope_inst)
{

    Packet * it;
    int len = 0;
    for(int q = 0; q < IFQ_MAX; q++) {
	if(prq_snd_[q].ifq_len > 0) {
	    len += prq_snd_[q].ifq_len;
	    it = prq_snd_[q].ifq_head;
	    
	    while(it != NULL) {
		cout << setw(10) << Scheduler::instance().clock()
		     << setw(3) << HDR_CMN(it)->ptype()
		     << setw(8) << HDR_CMN(it)->uid_
		     << setw(8) << HDR_CMN(it)->cope_pkt_id() 
		     << setw(8) << HDR_CMN(it)->next_hop()<< endl;

		it = it->next_;
	    }
	}
	cout << endl;
    }
}

/*
 * This is called by cope_prq_senddown or recvHigh/NormalPriority
 */
void COPEPriQueue::cope_enqueue(Packet *p, bool rt, COPE * cope_inst) {

    cope_inst->ctrl_pkt_timer_.stop();

    if(dsr_) {      //DSR


        if(cope_lookup_item(p) == true) // this item existed already
	    return;

	if((int)HDR_COPE(p)->encoded_num_ > 0) {
	    HDR_COPE(p)->encoded_num_ = 0;
	    //	    cout << "";
	    return;
	}
        
	/* get the rank of queue and fetch the corresponding ifq */
        int q = prq_assign_queue(p); // must be IFQ_NORMAL
        struct ifqueue *ifq = &prq_snd_[q];	

	/* drop the packet if ifq is full */

        if(IF_QFULL(ifq)) {

	    // cout << "---FULL---" << endl;
	    // showQueue(cope_inst);
            IF_DROP(ifq);
	    CMUPriQueue::drop(p, DROP_IFQ_QFULL);
            return;
        }

	
	if( HDR_IP(p)->saddr() == cope_inst->node_->address() 
	    && HDR_COPE(p)->ctype_ == COPE_DATA ) {
	    cope_inst->set_pkt_header(p);
	}
	


	/* 
         * push back the packet into the queue, if it is an retransmission 
         * packet, put it to head of queue 
         */
        if(rt) {
	    IF_ENQUEUE_HEAD(ifq, p);
        } else { 
	    IF_ENQUEUE(ifq, p);
        }

	if(HDR_COPE(p)->ctype_ != COPE_CTRL) {
	    cope_vir_table_->enque_vir_pkt(p, rt); // insert packet to virQueue
	    // if((int)HDR_COPE(p)->encoded_num_ > 0) {
	    // 	cout << "Enque: node: " << cope_inst->node_->nodeid()
	    // 	     << " num: " << (int)HDR_COPE(p)->encoded_num_
	    // 	     << " uid: " << HDR_CMN(p)->uid_
	    // 	     << " pre: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
	    // 	     << " next: " << HDR_CMN(p)->next_hop()
	    // 	     << endl;
	    // }
	}
	
	if(HDR_COPE(p)->ctype_ == COPE_DATA) {

	    // in pool the packet
	    if(cope_inst->node_->nodeid() == HDR_IP(p)->saddr() ) {
		// cout << "e " << HDR_CMN(p)->cope_pkt_id() 
		//      << " " << HDR_CMN(p)->uid_
		//      << " " << CUR_TIME << " "
		//      << " prev: " 
		//      << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		//      <<" next: " 
		//      << HDR_CMN(p)->next_hop() << endl;
		cope_inst->pkt_pool_->in_pool(p, cope_inst);
	    }
	
	}
 
	// showQueue(cope_inst);


	// cope_vir_table_->show();
	
    } else {      //NON-DSR
	/* 
	 * push back the packet into the queue, if it is an retransmission 
	 * packet or high priority packet , put it to head of queue 
	 */
	if(rt) {
	    q_->enqueHead(p);  //PacketQueue's enqueHead
	    if (q_->length() >= qlim_) {
		Packet *to_drop = q_->lookup(q_->length()-1);
		q_->remove(to_drop);
		PriQueue::drop(to_drop);
	    }
	} else { 
	    enque(p);  //DropTail's enque
	}

    }
}

bool COPEPriQueue::cope_lookup_item(Packet * p) {
    
    /*
     * the return packet, it is not necessary, since no packet data xor
     * operation happen, just simulate 
     */
    if(dsr_) { // DSR protocol, use CMUPriQueue
	int q;
	for(q = 0; q < IFQ_MAX; q++) {
	    Packet * iter =  prq_snd_[q].ifq_head;		
	    while( iter != NULL ) {	
		if(HDR_CMN(iter)->uid_ == HDR_CMN(p)->uid_)		
		    return true;
		iter = iter->next_;
	    }
	}
	
    } else { //Non-DSR protocol     
      
    }
    
    return false;   
}

/*
 * dequeue an item from output queue, this is called by cope, when a packet
 * in output queue is encoded, it will call cope_vir_dequeue to synchronize
 * virtual queue
 */
Packet * COPEPriQueue::cope_dequeue_item(Packet * p) {
    
    /*
     * the return packet, it is not necessary, since no packet data xor
     * operation happen, just simulate 
     */

    if(dsr_) { // DSR protocol, use CMUPriQueue
        int q;
        for(q = 0; q < IFQ_MAX; q++) {
            if(prq_snd_[q].ifq_len > 0) {
                //              IF_DEQUE_ITEM(&prq_snd_[q], Packet, p, res);
                Packet* iter =  prq_snd_[q].ifq_head;
                Packet* prev_iter = iter; 
                while( iter != NULL ) {
                    if(HDR_CMN(iter)->uid_ == HDR_CMN(p)->uid_) {
                        if(iter == prq_snd_[q].ifq_head) {
                            //IF_DEQUEUE(&prq_snd_[q], res);
                            if ((prq_snd_[q].ifq_head = iter->next_) == 0)
                                prq_snd_[q].ifq_tail = 0;
                        } else if(iter == prq_snd_[q].ifq_tail) {
                            prq_snd_[q].ifq_tail = prev_iter;
                            prev_iter->next_ = 0;
                        } else {
                            prev_iter->next_ = iter->next_;
                        }
                        iter->next_ = 0;
                        prq_snd_[q].ifq_len--;
                        return iter;
                    }
                    prev_iter = iter;
                    iter = iter->next_;
                }
            }
        }
    } else { //Non-DSR protocol     
        q_->remove(p);  // remove a specific packet from packet queue
    }
    // showQueue();
    //    cope_vir_table_->remove_vir_pkt(p);  // synchronize the virtual queue
    //showQueue();
    return NULL;
}


/*
 * called by cope_resume
 */
void COPEPriQueue::cope_prq_resume(COPE * cope_inst) {

   
    if(dsr_) { //DSR
	Packet *p;
	assert(prq_blocked_);
#if PRIQUEUE_DEBUG > 0
	prq_validate();
#endif
	
	p = prq_dequeue();
      
	if (p != 0) {

	    if(isEmpty())
		cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
	
	    stat_send_++;
	    if(HDR_COPE(p)->ctype_ != COPE_CTRL) {
		// cout << "Resume->time: " << CUR_TIME
		//      << " node: " << cope_inst->node_->nodeid()
		//      << " uid: " << HDR_CMN(p)->uid_
		//      << " ptype: " << HDR_CMN(p)->ptype()
		//      << " size " << HDR_CMN(p)->size()
		//      << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		//      << " next: " << HDR_CMN(p)->next_hop();
		// if(HDR_CMN(p)->ptype() == PT_TCP)
		//     cout << " TCP seq: " << HDR_TCP(p)->seqno();
		// else if(HDR_CMN(p)->ptype() == PT_ACK)
		//     cout << " ACK seq: " << HDR_TCP(p)->seqno();
		// cout << endl;

		// if(HDR_CMN(p)->uid_ == 7199)
		//     cout << "";
		
		// synchronize virtual queue
		cope_vir_table_->remove_vir_pkt(p); 		
	    }
	
	    prq_blocked_ = 1;
	    stat_send_++;
		
	    // not encode packets, send out directly
	    if( HDR_CMN(p)->ptype() != PT_CBR
                && HDR_CMN(p)->ptype() != PT_ACK
                && HDR_CMN(p)->ptype() != PT_TCP
		&& HDR_CMN(p)->ptype() != PT_COPE ) {
		    
		// cout << HDR_CMN(p)->cope_pkt_id()
		//      << " " << HDR_CMN(p)->uid_
		//      << " " << HDR_CMN(p)->ptype()
		//      << " " << CUR_TIME << " "
		//      << " prev: " 
		//      << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		//      << " next: " 
		//      << HDR_CMN(p)->next_hop() << endl;

		CMUPriQueue::target_->recv(p, (Handler*)&prq_qh_);
		return;
	    }

	    /*
	     * Use original packet p here, since we just simulate the xor 
	     * operation and no further use for p, otherwise send_pkt 
	     * should be a copy of p
	     * 
	     * The returned send packet should be original p or a encoded p.
	     *
	     * If need, packet cope will be operated inside encoding process
	     */
	
	    Packet * send_pkt = p->copy();
	    // to get the maximal length's packet
	    Packet * max_size_pkt = send_pkt; 
		
	    int encoded = 0;
	    double timeout;
	
	    encoded = cope_prq_encode(p, 
				      cope_inst, 
				      &send_pkt, 
				      &max_size_pkt);
	    

	    

	    /* target_ is a member of Connector */
	    if(encoded) {
		    
		timeout = cope_inst->txtime(max_size_pkt);
		    
		// if(HDR_CMN(send_pkt)->uid_ == 11325 && cope_inst->node_->nodeid() == 2)
		// cout << "Resume--> " 
		//      << " time: " << CUR_TIME
		//      << " copeid: " << HDR_CMN(send_pkt)->cope_pkt_id() 
		//      << " uid: " << HDR_CMN(send_pkt)->uid_
		//      << " ptype: " << HDR_CMN(send_pkt)->ptype()       
		//      << " prev: " 
		//      << ETHER_ADDR(HDR_MAC802_11(send_pkt)->dh_ta)
		//      << " -->next: " 
		//      << HDR_CMN(send_pkt)->next_hop() << endl;


		// cout << HDR_CMN(send_pkt)->cope_pkt_id() 
		//      << " " << HDR_CMN(send_pkt)->uid_
		//      << " " << HDR_CMN(send_pkt)->ptype()       
		//      << " " << CUR_TIME << " "
		//      << " prev: " 
		//      << ETHER_ADDR(HDR_MAC802_11(send_pkt)->dh_ta)
		//      << " next: " 
		//      << HDR_CMN(send_pkt)->next_hop() << endl;
	      
		CMUPriQueue::target_->recv(send_pkt, (Handler*)&prq_qh_);
		/* send an encoded packet, should set the timer */
		cope_inst->start_timer(send_pkt, timeout);
	    } else {
	
		Packet::free(send_pkt);	
		    
		// cout << " copeid: " << HDR_CMN(p)->cope_pkt_id() 
		//      << " uid: " << HDR_CMN(p)->uid_
		//      << " pt: " << HDR_CMN(p)->ptype()
		//      << " time: " << CUR_TIME << " "
		//      << " prev: " 
		//      << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)     
		//      << " next: " 
		//      << HDR_CMN(p)->next_hop()
		//      << " acknum: " << (int)HDR_COPE(p)->ack_num_
		//      << endl;
		    
		CMUPriQueue::target_->recv(p, (Handler*)&prq_qh_);
	    }
	} else {
	    prq_blocked_ = 0;
	}
    } else {  // NON-DSR

	double now = Scheduler::instance().clock();
	Packet* p = deque();
	// if(length() == 0)
	//     cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
	if(p)
	    cope_vir_table_->remove_vir_pkt(p);

	if (p != 0) {
	    /*
	     * Use original packet p here, since we just simulate the xor operation and 
	     * no further use for p, otherwise send_pkt should be a copy of p
	     */    
	    // Packet * send_pkt = p;
	    // int encoded = 0;
	    Packet * send_pkt = p->copy();
	    Packet * max_size_pkt = send_pkt;
	    int encoded = 0;
	    double timeout;
	    /* cope encode downside packet */
	    if( HDR_COPE(p)->ctype_ != COPE_CTRL ) 
		encoded = cope_prq_encode(p,cope_inst,&send_pkt, &max_size_pkt);
	    /* send out */
	    PriQueue::target_->recv(send_pkt, (QueueHandler*)(&cope_inst->h_cope_));

	    if(encoded) {
	        timeout = cope_inst->txtime(max_size_pkt);
	        /* send an encoded packet, should set the timer */
	        cope_inst->start_timer(send_pkt, timeout);	       
	    }  /* else send a native packet, no need for timer */ 

	} else {
	    if (unblock_on_resume_) {
		utilUpdate(last_change_, now, blocked_);
		last_change_ = now;
		blocked_ = 0;

	    } else {
		utilUpdate(last_change_, now, blocked_);
		last_change_ = now;
		blocked_ = 1;
	    }
	}
    }

}

bool COPEPriQueue::isEmpty(){
    // bool empty = true;
    // // for dsr, just check IFQ_NORMAL which means PT_CBR & PT_COPE here.
    // if(dsr_) { 
    // 	if(prq_snd_[IFQ_NORMAL].ifq_len > 0) {
    // 	    empty = false;
    // 	} else {
    // 	    empty = true;
    // 	}
    // }

    // return empty;

    if(dsr_) {
	int q;
	for(q = 0; q < IFQ_MAX; q++) {
	    if(prq_snd_[q].ifq_len > 0) {
		return true;
	    }
	}    
	return false;	
    }
    return true;
}

Packet* COPEPriQueue::prq_dequeue() {
 
    Packet *p = NULL;
    int q;
    
    for(q = 0; q < IFQ_MAX; q++) {
	if(prq_snd_[q].ifq_len > 0) {
	    IF_DEQUEUE(&prq_snd_[q], p);
	    return p;
	}
    }    


    return NULL;
}

/* 
 * put the packet into output queue, and deque the head packet,
 * sent it down to mac layer
 */
void COPEPriQueue::cope_prq_senddown(Packet * p, COPE * cope_inst) {    
  
    if(dsr_) {   // dsr protocol, use CMUPriQueue
      
#if PRIQUEUE_DEBUG > 0
        prq_validate();
#endif       
        stat_recv_++;  //update state
      
        if(prq_blocked_ == 1) {
            stat_blocked_++;
        } else {
	    assert(prq_length() == 0);
        }

        if(HDR_COPE(p)->ctype_ == COPE_DATA) {
	    cope_enqueue(p, false, cope_inst); //insert packet to cope-queue
	} else {
	    cope_enqueue(p, true, cope_inst); //insert packet to cope-queue	
	}
	
        /*
         * Start dequeue if idle...
         */
        if(prq_blocked_ == 0) {

            p = prq_dequeue();  // use CMU-PriQueue's dequeue method directly
	    
	    if(p) {	       
	        if(HDR_COPE(p)->ctype_ != COPE_CTRL)
		    // synchronize virtual queue
		    cope_vir_table_->remove_vir_pkt(p);
	

		prq_blocked_ = 1;
		stat_send_++;
		
		// not encode packets, send out directly
		if( HDR_CMN(p)->ptype() != PT_CBR
		    && HDR_CMN(p)->ptype() != PT_ACK
		    && HDR_CMN(p)->ptype() != PT_TCP
		    && HDR_CMN(p)->ptype() != PT_COPE ) {
		    
		    // cout << HDR_CMN(p)->cope_pkt_id()
		    // 	 << " " << HDR_CMN(p)->uid_
		    // 	 << " " << HDR_CMN(p)->ptype()
		    // 	 << " " << CUR_TIME << " "
		    // 	 << " prev: " 
		    // 	 << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		    // 	 << " next: " 
		    // 	 << HDR_CMN(p)->next_hop() << endl;
	
		    CMUPriQueue::target_->recv(p, (Handler*)&prq_qh_);

		    return;
		}

		// if(HDR_COPE(p)->ctype_ == COPE_CTRL)
		//     cout << HDR_CMN(p)->cope_pkt_id() 
		// 	 << " " << HDR_CMN(p)->size()
		// 	 << endl;

		/*
		 * Use original packet p here, since we just simulate the xor 
		 * operation and no further use for p, otherwise send_pkt 
		 * should be a copy of p
		 * 
		 * The returned send packet should be original p or a encoded p.
		 *
		 * If need, packet cope will be operated inside encoding process
		 */

	
		Packet * send_pkt = p->copy();
		// to get the maximal length's packet
		Packet * max_size_pkt = send_pkt; 
		
		int encoded = 0;
		double timeout;

		encoded = cope_prq_encode(p, 
					  cope_inst, 
					  &send_pkt, 
					  &max_size_pkt);


		/* target_ is a member of Connector */
		if(encoded) {
		    
		    timeout = cope_inst->txtime(max_size_pkt);

		    // if(HDR_CMN(send_pkt)->uid_ == 11325 && cope_inst->node_->nodeid() == 2)
		    // cout << "Send-->"
		    // 	 << " time: " << CUR_TIME
		    // 	 << " copeid: " << HDR_CMN(send_pkt)->cope_pkt_id() 
		    // 	 << " uid: " << HDR_CMN(send_pkt)->uid_
		    // 	 << " ptype: " << HDR_CMN(send_pkt)->ptype()       
		    // 	 << " prev: " 
		    // 	 << ETHER_ADDR(HDR_MAC802_11(send_pkt)->dh_ta)
		    // 	 << " -->next: " 
		    // 	 << HDR_CMN(send_pkt)->next_hop() << endl;
			 
		    
		    CMUPriQueue::target_->recv(send_pkt, (Handler*)&prq_qh_);
		    
		    /* send an encoded packet, should set the timer */
		    cope_inst->start_timer(send_pkt, timeout);
		
		} else {
	
		    Packet::free(send_pkt);	
		    
		    // cout << HDR_CMN(p)->cope_pkt_id() 
		    // 	 << " " << HDR_CMN(p)->uid_
		    // 	 << " " << HDR_CMN(p)->ptype()
		    // 	 << " " << CUR_TIME << " "
		    // 	 << " prev: " 
		    // 	 << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)     
		    // 	 << " next: " 
		    // 	 << HDR_CMN(p)->next_hop() << endl;
		    

		    CMUPriQueue::target_->recv(p, (Handler*)&prq_qh_);

		}
	    }
	}
#if PRIQUEUE_DEBUG > 0
	prq_validate();
#endif

    } else {  // other protocols except dsr, use PriQueue      

	// 	if (HDR_COPE(p)->ctype_ != COPE_DATA){
	// 	    recvHighPriority(p, cope_inst);
	// 	    return;
	// 	}
	
	// 	struct hdr_cmn *ch = HDR_CMN(p);

	// 	if(Prefer_Routing_Protocols) {
	// 	    switch(ch->ptype()) {
	// 	    case PT_DSR:
	// 	    case PT_MESSAGE:
	// 	    case PT_TORA:
	// 	    case PT_AODV:
	// 	    case PT_AOMDV:
	// 		recvHighPriority(p, cope_inst);
	// 		break;
	// 	    default:
	// 		recvNormalPriority(p, cope_inst);
	// 	    }
	// 	}
    }
}

/* return 1: send an encoded packet; return 0: send a native packet */
int COPEPriQueue::cope_prq_encode(Packet * p,
				  COPE * cope_inst, 
				  Packet ** send_pkt,
				  Packet ** max_size_pkt) {
 
    int encoded = 0; // native packet by default

    /*  if return 1, send_pkt is the encoded packet with:
     *    0.delete the encoded packet from output and virtual queue
     *    1.packet data encoded.
     *    2.xored header set.
     *    3.local seq of each encoded packet's nexthop updated
     *    4.ack of each encoded packet inserted
     *  otherwise, send_pkt = p, return 0
     */

    if(HDR_COPE(p)->ctype_ != COPE_CTRL)
	encoded = cope_inst->encode(p, send_pkt, max_size_pkt);

    /* no matter a encoded packet or not, put append 
       acks and state report into cope header */

    if(encoded) {

	cope_inst->append_acks(*send_pkt);
	cope_inst->append_state_report(*send_pkt);

    } else {

	cope_inst->append_acks(p);
	cope_inst->append_state_report(p);

    }
    
    return encoded; 
}


/*
 * Increase the neighbor-seqnum-counter, and then call the NonAckQueue's
 * enqueue function.
 */
void COPEPriQueue::enqueue_non_ack(int nodeid, Packet* p) {
    // neighbor_seqnum_counter_ ++;
    // non_acks_->enqueue(nodeid, neighbor_seqnum_counter_, p);
}

void COPEPriQueue::recvNormalPriority(Packet* p, COPE * cope_inst) {
    double now = Scheduler::instance().clock();
    double timeout = cope_inst->txtime(p);   
    cope_enqueue(p, false, cope_inst);    
    if (!blocked_) {
	/*
	 * We're not blocked.  Get a packet and send it on.
	 * We perform an extra check because the queue
	 * might drop the packet even if it was
	 * previously empty!  (e.g., RED can do this.)
	 */
	p = deque();//DropTail's deque

	if(length() == 0)
	    cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);

	if(p)
	    cope_vir_table_->remove_vir_pkt(p);

	if (p != 0) {
	    utilUpdate(last_change_, now, blocked_);
	    last_change_ = now;
	    blocked_ = 1;
	    /*
	     * Use original packet p here, since we just simulate the xor 
	     * operation and no further use for p, otherwise send_pkt should
	     * be a copy of p
	     */	    
	    Packet * send_pkt = p->copy();
	    Packet * max_size_pkt = send_pkt;
	    /* cope encode downside packet */
	    int encoded = cope_prq_encode(p,cope_inst,&send_pkt, &max_size_pkt);

	    // actually the downtarget_
	    PriQueue::target_->recv(send_pkt, (Handler*)&qh_);
	    if(encoded) {
		/* send an encoded packet, should set the timer */
		cope_inst->start_timer(send_pkt, timeout);
	    } /* else send a native packet, no need for timer */
	

	}
    }
}

/* 
 * call Connector::drop(), actually multi inherit can not determine one
 * specific path, so we appoint a specific path according to routing protocol
 */
void COPEPriQueue::drop(Packet * p){
    if(dsr_)
	CMUPriQueue::drop(p);
    else
	PriQueue::drop(p);
}

void COPEPriQueue::recvHighPriority(Packet* p, COPE * cope_inst) {
    double timeout = cope_inst->txtime(p);
    cope_enqueue(p, true, cope_inst);
  
    if (!blocked_) {
	/*
	 * We're not blocked.  Get a packet and send it on.
	 * We perform an extra check because the queue
	 * might drop the packet even if it was
	 * previously empty!  (e.g., RED can do this.)
	 */
	p = deque();
	// if(length() == 0)
	//     cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
        if(p)
	    cope_vir_table_->remove_vir_pkt(p);
	if (p != 0) {
	    blocked_ = 1;
	    /*
	     * Use original packet p here, since we just simulate the xor 
	     * operation and no further use for p, otherwise send_pkt should
	     * be a copy of p
	     */
	    Packet * send_pkt = p->copy();
	    Packet * max_size_pkt = send_pkt;

	    int encoded = 0;
	    /* cope encode downside packet */
	    if(HDR_COPE(p)->ctype_ != COPE_CTRL)
		encoded = cope_prq_encode(p,cope_inst,&send_pkt, &max_size_pkt);
	    PriQueue::target_->recv(send_pkt, (Handler*)(&qh_));
	    if(encoded) {
		/* send an encoded packet, should set the timer */
		cope_inst->start_timer(send_pkt, timeout);
	    } /* else send a native packet, no need for timer */
	

	}
    }

}

void COPEPriQueue::resume(){
    if(h_cope_)
	h_cope_->handle((Event*) 0);
}

void COPEPriQueue::prq_resume(){
    if(h_cope_) {
	h_cope_->handle((Event*) 0);
    }
}



#endif
